package org.infodavid.common.ejb;

import java.util.List;

import javax.ejb.Local;
import javax.ejb.PrePassivate;
import javax.persistence.CollectionTable;
import javax.persistence.Column;
import javax.persistence.ColumnResult;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedNativeQueries;
import javax.persistence.NamedNativeQuery;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.SqlResultSetMapping;
import javax.persistence.SqlResultSetMappings;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.persistence.UniqueConstraint;
import javax.persistence.Version;

import org.hibernate.annotations.ForeignKey;
import org.hibernate.annotations.Index;
import org.hibernate.annotations.OnDelete;
import org.hibernate.annotations.OnDeleteAction;
import org.hibernate.annotations.OptimisticLockType;
import org.hibernate.annotations.Persister;
import org.hibernate.annotations.Type;
import org.joda.time.DateTime;

import org.infodavid.common.ejb.components.GenericPropertyComponent;
import org.infodavid.common.impl.model.ApplicationSettingsImpl;
import org.infodavid.common.model.IApplicationSettings;
import org.infodavid.common.model.IGenericPropertiesMap;
import org.infodavid.common.model.IGenericProperty;
import org.infodavid.common.model.IOrganization;
import org.infodavid.common.model.impl.persisters.VersionSafeSingleTableEntityPersister;
import org.infodavid.common.persistence.ApplicationSettingsDataService;
import org.infodavid.common.persistence.INamed;

/**
 * The Class ApplicationSettingsBean.
 */
@Entity(name = "IApplicationSettings")
@org.hibernate.annotations.Entity(dynamicUpdate = true, selectBeforeUpdate = true, dynamicInsert = true, optimisticLock = OptimisticLockType.VERSION)
@Persister(impl = VersionSafeSingleTableEntityPersister.class)
@Table(name = "APPLICATION_SETTINGS")
@NamedQueries(value = {
    @NamedQuery(name = ApplicationSettingsDataService.QUERY_FIND_COUNT, query = "select count(d."
        + IApplicationSettings.KEY + ") from IApplicationSettings d"),
    @NamedQuery(name = ApplicationSettingsDataService.QUERY_FIND, query = "select d from IApplicationSettings d"),
    @NamedQuery(name = ApplicationSettingsDataService.QUERY_FIND_ACTIVE_COUNT, query = "select count(d."
        + IApplicationSettings.KEY + ") from IApplicationSettings d where d.archived = 0"),
    @NamedQuery(name = ApplicationSettingsDataService.QUERY_FIND_ACTIVE, query = "select d from IApplicationSettings d where d.archived = 0"),
    @NamedQuery(name = ApplicationSettingsDataService.QUERY_FIND_BY_PRODUCT, query = "select d from IApplicationSettings d where d.archived = 0 and :"
        + IApplicationSettings.PRODUCT
        + " is not null and d."
        + IApplicationSettings.PRODUCT
        + " = :" + IApplicationSettings.PRODUCT),
    @NamedQuery(name = ApplicationSettingsDataService.QUERY_FIND_BY_CREATION_DATE, query = "select d from IApplicationSettings d where d.archived = 0 and d."
        + IApplicationSettings.CREATION_DATE + " between :date1 and :date2"),
    @NamedQuery(name = ApplicationSettingsDataService.QUERY_FIND_BY_CREATION_DATE_COUNT, query = "select count(d."
        + IApplicationSettings.KEY
        + ") from IApplicationSettings d where d.archived = 0 and d."
        + IApplicationSettings.CREATION_DATE + " between :date1 and :date2"),
    @NamedQuery(name = ApplicationSettingsDataService.QUERY_FIND_BY_MODIFICATION_DATE, query = "select d from IApplicationSettings d where d.archived = 0 and d."
        + IApplicationSettings.MODIFICATION_DATE + " between :date1 and :date2"),
    @NamedQuery(name = ApplicationSettingsDataService.QUERY_FIND_BY_MODIFICATION_DATE_COUNT, query = "select count(d."
        + IApplicationSettings.KEY
        + ") from IApplicationSettings d where d.archived = 0 and d."
        + IApplicationSettings.MODIFICATION_DATE + " between :date1 and :date2"),
    @NamedQuery(name = ApplicationSettingsDataService.QUERY_FIND_FIRST, query = "select d from IApplicationSettings d where d.archived = 0 and d."
        + IApplicationSettings.ORGANIZATION + " is not null"),
    @NamedQuery(name = ApplicationSettingsDataService.QUERY_FIND_PROPERTIES, query = "select elements(p) from IApplicationSettings a"
        + " join a.genericData p where (:"
        + IApplicationSettings.PRODUCT
        + " is null or a."
        + IApplicationSettings.PRODUCT
        + " like :"
        + IApplicationSettings.PRODUCT
        + ") and (:"
        + IGenericProperty.SCOPE
        + " is null or p."
        + IGenericProperty.SCOPE
        + " like :"
        + IGenericProperty.SCOPE
        + ") and (:"
        + IGenericProperty.NAME
        + " is null or p."
        + IGenericProperty.NAME + " like :" + IGenericProperty.NAME + ')')
})
@SqlResultSetMappings({
	@SqlResultSetMapping(name = "IApplicationSettings.propertyValue", columns = @ColumnResult(name = "value"))
})
@NamedNativeQueries(value = {
	@NamedNativeQuery(name = ApplicationSettingsDataService.QUERY_FIND_GLOBAL_PROPERTY, query = "select distinct(p.value) as value from APPLICATION_SETTINGS_PROPERTIES p where p.name like :property and p.value is not null", resultSetMapping = "IApplicationSettings.propertyValue")
})
@Local(value = IApplicationSettings.class)
public class ApplicationSettingsBean extends ApplicationSettingsImpl {

	/** The Constant serialVersionUID. */
	private static final long serialVersionUID = 1661345027625851664L;

	/**
	 * The Constructor.
	 * @throws Exception the exception
	 */
	protected ApplicationSettingsBean() throws Exception {
		super();
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.impl.model.ApplicationSettingsImpl#init()
	 */
	@Override
	@PrePassivate
	public void init() throws Exception {
		super.init();
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.impl.model.DataObjectImpl#getCreationDate()
	 */
	@Override
	@Column(name = CREATION_DATE, nullable = false, updatable = false)
	@Type(type = "org.infodavid.persistence.impl.hibernate.usertype.DateTimeUserType")
	@Index(name = "IDX_APPLICATION_SETTINGS_CREATIONDATE")
	public DateTime getCreationDate() {
		return super.getCreationDate();
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.impl.model.DataObjectImpl#getModificationDate()
	 */
	@Override
	@Version
	@Column(name = MODIFICATION_DATE, nullable = false)
	@Type(type = "org.infodavid.persistence.impl.hibernate.usertype.DateTimeUserType")
	public DateTime getModificationDate() {
		return super.getModificationDate();
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.impl.model.DataObjectImpl#getKey()
	 */
	@Override
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name = ID, nullable = false)
	public Long getKey() {
		return super.getKey();
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.impl.model.DataObjectImpl#isArchived()
	 */
	@Override
	@Column(name = ARCHIVED, nullable = false)
	@Index(name = "IDX_APPLICATION_SETTINGS_ARCHIVED")
	public boolean isArchived() {
		return super.isArchived();
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.impl.model.ApplicationSettingsImpl#getName()
	 */
	@Override
	@Column(name = PRODUCT, length = 32, nullable = false, updatable = true)
	@Index(name = "IDX_APPLICATION_SETTINGS_PRODUCT")
	public String getProduct() {
		return super.getProduct();
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.impl.model.ApplicationSettingsImpl#getProperties()
	 */
	@Override
	@Transient
	public IGenericPropertiesMap getProperties() {
		return super.getProperties();
	}

	/**
	 * Gets the generic data.
	 * @return the data
	 */
	@ElementCollection(fetch = FetchType.LAZY, targetClass = GenericPropertyComponent.class)
	@CollectionTable(name = "APPLICATION_SETTINGS_PROPERTIES", joinColumns = @JoinColumn(name = ID, nullable = false), uniqueConstraints = @UniqueConstraint(name = "UC_APPLICATION_SETTINGS_PROPERTIES", columnNames = {
	    INamed.NAME, ID
	}))
	@ForeignKey(name = "FK_APPLICATION_SETTINGS_PROPERTIES")
	protected List<IGenericProperty> getGenericData() {
		return super.getProperties().getData();
	}

	/**
	 * Sets the generic data.
	 * @param values the values
	 */
	protected void setGenericData(final List<IGenericProperty> values) {
		super.getProperties().setData(values);
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.impl.model.ApplicationSettingsImpl#getOrganization()
	 */
	@Override
	@JoinColumn(name = IOrganization.ID, referencedColumnName = IOrganization.ID, nullable = true)
	@ManyToOne(targetEntity = OrganizationBean.class, fetch = FetchType.LAZY)
	@OnDelete(action = OnDeleteAction.CASCADE)
	@ForeignKey(name = "FK_APPLICATION_SETTINGS_ORGANIZATION")
	public IOrganization getOrganization() {
		return super.getOrganization();
	}
}
